@file:Suppress("NOTHING_TO_INLINE")

package org.glavo.bot

import io.ktor.util.*
import kotlinx.coroutines.launch
import net.mamoe.mirai.message.data.EmptyMessageChain
import net.mamoe.mirai.message.data.Message
import net.mamoe.mirai.message.data.PlainText
import net.mamoe.mirai.message.data.at
import org.glavo.bot.data.Advancements
import org.glavo.bot.data.Death
import org.glavo.bot.data.Player
import org.intellij.lang.annotations.Language
import java.util.*
import java.util.regex.Matcher
import java.util.regex.Pattern

private const val AdministratorName = "The_Fool"
private const val joinGameTimeout = 15 * 1000L

private inline fun MutableList<Pair<Pattern, (Matcher) -> Unit>>.match(
    @Language("RegExp") pattern: String,
    noinline action: (Matcher) -> Unit
) {
    this += Pair(Pattern.compile(pattern), action)
}

private val matchers: Array<Pair<Pattern, (Matcher) -> Unit>> = arrayListOf<Pair<Pattern, (Matcher) -> Unit>>().apply {
    var zzz = 0L
    match("(\\[Not Secure] )?<(?<name>$NamePattern)> (?<info>.*)") { m1 ->
        val name = m1.group("name")!!
        val info = m1.group("info")!!

        if (info.startsWith(";;") || info.startsWith("；；")) {
            if (info == ";;Test" && (name in Player.Glavo.names)) {
                val f = bot.getFriend(360736041L)
                if (f != null) {
                    bot.launch { f.sendMessage("测试消息接收成功") }
                }
            }
            return@match
        }

        if (info.indexOf('@') < 0) {
            bot.launch {
                MainGroup.sendMessage("$name: $info")
            }

            if (info == "zzz") {
                val t = System.currentTimeMillis()
                if (t - zzz > 15 * 1000L) {
                    zzz = t
                    bot.launch {
                        try {
                            rcon("title @a[scores={Dimension=1}] title \"zzz\"")
                        } catch (e: Throwable) {
                            bot.logger.warning(e)
                        }
                    }
                }
            }
        } else {
            val group = MainGroup
            var res: Message = EmptyMessageChain
            var offset = 0

            val m = AtPattern.matcher(info)
            while (m.find()) {
                val start = m.start()
                val end = m.end()

                if (start > offset) {
                    res += PlainText(info.substring(offset, start))
                }
                offset = end

                val n = m.group("name")

                val qn = n.toLongOrNull()
                if (qn != null) {
                    val mem = group[qn]
                    if (mem != null) {
                        res += mem.at()
                        continue
                    }
                }

                var p = Player.All.firstOrNull { pl -> pl.names.any { it.equals(n, true) } }
                if (p != null) {
                    val mem = group[p.qq]
                    if (mem != null) {
                        res += mem.at()
                        continue
                    }
                }

                p = Player.All.firstOrNull { pl -> pl.nicknames.any { it.equals(n, true) } }
                if (p != null) {
                    val mem = group[p.qq]
                    if (mem != null) {
                        res += mem.at()
                        continue
                    }
                }

                res += PlainText(info.substring(start, end))
            }

            if (offset < info.length) {
                res += info.substring(offset, info.length)
            }

            bot.launch {
                group.sendMessage(PlainText("$name: ") + res)
            }
        }
    }

    val lastJoinTimes: MutableMap<String, Long> = mutableMapOf()
    match("(?<name>$NamePattern) joined the game") {
        val current = System.currentTimeMillis()
        val name = it.group("name")!!

        val prev = lastJoinTimes.put(name, current)
        if (prev == null || current - prev > joinGameTimeout)
            bot.launch { MainGroup.sendMessage("$name 进入服务器") }
    }

    val lastLeftTimes: MutableMap<String, Long> = mutableMapOf()
    match("(?<name>$NamePattern) left the game") {
        val current = System.currentTimeMillis()
        val name = it.group("name")!!

        val prev = lastLeftTimes.put(name, current)
        if (prev == null || current - prev > joinGameTimeout)
            bot.launch { MainGroup.sendMessage("$name 离开服务器") }
    }

    match("(?<name>$NamePattern) has made the advancement \\[(?<adv>[^]]+)]") { m ->
        val name = m.group("name")
        if (name != AdministratorName) {
            val adv = m.group("adv").let { Advancements[it] ?: it }
            bot.launch { MainGroup.sendMessage("$name 取得了进度「$adv」") }

        }
    }

    match("(?<name>$NamePattern) has completed the challenge \\[(?<adv>[^]]+)]") { m ->
        val name = m.group("name")
        if (name != AdministratorName) {
            val adv = m.group("adv").let { Advancements[it] ?: it }
            bot.launch { MainGroup.sendMessage("$name 完成了挑战「$adv」") }

        }
    }

    match("(?<name>$NamePattern) has reached the goal \\[(?<adv>[^]]+)]") { m ->
        val name = m.group("name")
        if (name != AdministratorName) {
            val adv = m.group("adv").let { Advancements[it] ?: it }
            bot.launch { MainGroup.sendMessage("$name 达成了目标「$adv」") }

        }
    }

    match("Done \\([^)]+\\)! For help, type \"help\"") {
        if (rebooting.getAndSet(false)) {
            bot.launch {
                MainGroup.sendMessage("服务器重启完毕")
                CommandGroup.sendMessage("服务器重启完毕")
            }
        }
    }

//    val names: MutableSet<String> = mutableSetOf()
//    match(
//        "com.mojang.authlib.GameProfile@[0-9a-f]+\\[id=<null>,name=(?<name>$NamePattern),properties=\\{},legacy=false] \\([^)]*\\) lost connection: Disconnected"
//    ) { m ->
//        val name = m.group("name")!!
//        if (names.add(name)) {
//            val group = MainGroup
//
//            val a = Player.All.firstOrNull { it.names.contains(name) }
//                ?.let { group[it.qq]?.at() }
//                ?: PlainText("@$name ")
//
//            bot.launch { group.sendMessage(a + "登录服务器时如果提示“登录失败：无效会话”，请退出游戏，在启动器内删除账号并重新登录") }
//        }
//    }
}.toTypedArray()

@Language("RegExp")
const val NamePattern = "[a-zA-Z0-9_]+"

private val AtPattern: Pattern = Pattern.compile(
    "@(?<name>\\p{javaJavaIdentifierPart}+)"
)

private const val InfoStr = " [Server thread/INFO]: "

private var rebootMessageTime = 0L

fun matchLog(log: String) {
    if (log.length > 33 && log.startsWith(InfoStr, 10)) {
        val str = log.substring(33)

        for (m in matchers) {
            val matcher = m.first.matcher(str)
            if (matcher.matches()) {
                m.second.invoke(matcher)
                return
            }
        }
        bot.launch {
            val res = Death.match(str)
            if (res != null) {
                MainGroup.sendMessage(res)
            }
        }
    } else if (log == "!!STOP") {
        rebooting.set(true)
        val now = System.currentTimeMillis()
        if (now - rebootMessageTime >= 60 * 1000L) {
            rebootMessageTime = now
            bot.launch {
                MainGroup.sendMessage("服务器意外退出，正在重启中")
                CommandGroup.sendMessage("服务器意外退出，正在重启中")
            }
        }
        bot.logger.warning("服务器意外退出，正在重启中")
        return
    }
}
